/**
 * 基于redis实现的分布式锁
 */
import express from 'express'
import redis from 'redis'
import { promisify } from 'util'

const client = redis.createClient({
   host: "172.16.2.101",
   port: 32523,
   password: "123456"
 })

 client.on("error", (error) => {
   console.error(error)
 })

 client.get("name", function (err, reply) {
   console.log(err, reply)
 })

 client.setnx("name1", 'zheng111', (err, reply) => {
   console.log(err, reply)
 })

 function asyncClient (command: string) {
   return promisify((<any>client)[command]).bind(client)
 }

 async function sleep(time: number) {
   return new Promise((resolve: Function) => {
     setTimeout(() => {resolve()}, time)
   })
 }

 async function lock (key: string, value: string, expire: number): Promise<boolean> {
  let clientSet = promisify(client.set).bind(client)
  
  let res = await clientSet(key, value, 'EX', expire, 'NX')
  
  // 成功
  if (res == 'OK') {
    console.log("lock success", key, value)
    return true
  } else {
    console.log("lock failed, retry")
    await sleep(1000)
    return lock(key, value, expire)
  } 


 }

 async function unlock(key: string, value: string): Promise<boolean> {
   let lockValue = await asyncClient("get")(key)
   if (!lockValue) {
     return true
   } else if (lockValue != value) {
     return false
   } else {
     await asyncClient("del")(key)
     return false
   }
 }




 const app = express()

 app.get("/get", async (req, res) => {
  let count = await asyncClient("get")("count")
  if (count <= 0) {
    return res.send("no")
  }
  let lockKey = "count-lock"
  let lockValule: string = String(Date.now() + Math.random())
  let isLock = await lock(lockKey, lockValule, 5000)
  

  if (!isLock) {
    return res.send("failed")
  }
  count = await asyncClient("get")("count")
  if (count <= 0) {
    await unlock(lockKey, lockValule)
    return res.send("no")
  }
  await asyncClient("decr")("count")
  await unlock(lockKey, lockValule)
  return res.send("ok")
  
  
 })


 app.get("/bitmap", (req, res) => {
   
 })

 app.listen(3000, () => {
   console.log("The server is running at port 3000");
 })